﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using MIAP.DataAccess.Interfaces;
using MIAP.Entidades;
using MIAP.Entidades.TiposXML;
using Microsoft.SqlServer.Dts.Runtime;

namespace MIAP.Negocio.Utiles
{
    public class ExecutorDtsx : IDisposable
    {
        /// <summary>
        /// Lista de variables del paquete a ejecutar
        /// </summary>
        private List<string> _listaVariables { get; set; }

        /// <summary>
        /// objeto el cual contiene todos los variables
        /// </summary>
        private Variables _objetoVariables { get; set; }

        /// <summary>
        /// variable de aplicacion
        /// </summary>
        private Application _app;

        /// <summary>
        /// variable de paquete a ejecutar
        /// </summary>
        private Package _package;

        /// <summary>
        /// nombre de la variable Filename
        /// </summary>
        private string varFilePath;

        /// <summary>
        /// prefijo identificador de las variables en el usuario
        /// </summary>
        private string idVariablesUser;

        /// <summary>
        /// valor de la variable FileName
        /// </summary>
        private string _rutaArchivos;

        /// <summary>
        /// valor de la ruta donde se encontraran los archivos con extension dtsx
        /// </summary>
        private string _rutaProyectos;

        /// <summary>
        /// Ruta completa del paquete que vamos a ejecutar
        /// </summary>
        private string _paqueteEjecutar;

        /// <summary>
        /// diccionaro de las variabes y los valores que tendran una vez que sean asignados
        /// </summary>
        public Dictionary<string, string> ValoresYVariables;

        /// <summary>
        /// Obtiene los errores si es que hay en la ejecucion de los archivos
        /// </summary>
        public string Errores { get; set; }


        /// <summary>
        /// server de Bd de donde se cargará el paquete
        /// </summary>
        private string _serverPkg;


        /// <summary>
        /// dao para laobtencion de datos de configuracion
        /// </summary>
        private IConfiguracionDao daoConfiguracion;

        /// <summary>
        /// nombre del proyecto
        /// </summary>
        private string _nombreProyecto;

        /// <summary>
        /// nombre del archivo
        /// </summary>
        private string _archivoProyecto;

        private const string varBitacora = "Usr_Bitacora";

        public ExecutorDtsx( )
        {
            this._app = new Application();
            this.daoConfiguracion = DataAccessFactory.Instance.CreateConfiguracionDao();
            this.varFilePath = daoConfiguracion.GetNombreVarFileName().Descripcion;
            this.idVariablesUser = daoConfiguracion.GetIdentificadorVariabesUsuario().Descripcion;

            this._serverPkg = daoConfiguracion.GetNombreServerPkg().Descripcion;            

            ValoresYVariables = new Dictionary<string, string>();
            this._rutaArchivos = daoConfiguracion.GetRutaArchivos().Descripcion;
            this._rutaProyectos = daoConfiguracion.GetRutaPaquetes().Descripcion;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="rutaPaquetes"></param>
        /// <param name="nombrePaquete"></param>
        public ExecutorDtsx(string nombrePaquete, string nombreProy, string nombreArchivo)
            : this()
        {
            this._paqueteEjecutar = nombrePaquete;
            this._nombreProyecto = nombreProy;
            this._archivoProyecto = nombreArchivo;
        }

        /// <summary>
        /// Regresa el nombre de las variables que el paquete necesita para su ejecución
        /// </summary>
        /// <returns></returns>
        public List<string> GetUserVariables()
        {
            //this.LoadPackage();
            GetVariables();
            return
                (from string variable in _listaVariables
                 where variable != this.varFilePath
                 select variable.Replace(idVariablesUser, string.Empty))
                    .ToList();
        }

        public void SetValoresConocidos(VariablesConocidas variables)
        {
            foreach (string var in this._listaVariables)
            {
                if (var.ToLower().Contains("anio"))
                {
                    this.ValoresYVariables[var] = variables.Año;
                }
                else if (var.ToLower().Contains("mes"))
                {
                    this.ValoresYVariables[var] = variables.Mes;
                }
                else if (var.ToLower().Contains("user"))
                {
                    this.ValoresYVariables[var] = variables.User;
                }
                else if (var.ToLower().Contains("filename"))
                {
                    this.ValoresYVariables[var] = variables.Filename;
                }
                else if (var.ToLower().Contains("version"))
                {
                    this.ValoresYVariables[var] = variables.Version;
                }
                else if (var.ToLower().Contains("bitacora"))
                {
                    this.ValoresYVariables[var] = variables.IdBitacora.ToString();
                }
                else if (var.ToLower().Trim() == this.varFilePath.ToLower().Trim())
                {
                    this.ValoresYVariables[var] = this.GetFilePath(this._rutaArchivos);
                }
            }
        }

        /// <summary>
        /// Varifica si existen datos en las variables que no tienen nungun valor asignado.
        /// </summary>
        /// <returns></returns>
        public bool ExistenValoresVacios()
        {            
            return ValoresYVariables.Where(valoresYVariable => valoresYVariable.Key != varBitacora).
                Any(valoresYVariable => valoresYVariable.Value == string.Empty);
        }

        /// <summary>
        /// obtiene las variables del paquete
        /// </summary>
        private void GetVariables()
        {
            _listaVariables = this.daoConfiguracion.GetVariablesPaquete(this._nombreProyecto,this._archivoProyecto);
            _listaVariables.Add(varBitacora);
        }

        /// <summary>
        /// Ejecuta el paquete
        /// </summary>
        /// <returns>true si el paquete se ejecuto de marea correcta</returns>
        public bool ExecuteDtsx(Dictionary<string, string> poValoresVariables)
        {

            if (_listaVariables.Count <= 0)
            {
                this.GetVariables();
            }
            if (ValoresYVariables != null)
            {
                this.SetValoresVariables(poValoresVariables);
            }

            //Execute DTSX.
#if DEBUG
            return true;
#else
            var parametros = ConstruyeParametros();
            var proceso = new ImpersonateProcess(parametros);
            var resultado=proceso.EjecutaProceso();
            if (!resultado)
            {
                this.Errores = proceso.Errores;
            }
            return resultado;
#endif
        }

        /// <summary>
        /// construye los parametros que se le pasarán al proceso
        /// </summary>
        /// <returns></returns>
        private string ConstruyeParametros()
        {
            var parametros = new StringBuilder();

            parametros.Append("/dts");
            //parametros.Append(" ");
            parametros.Append(" \"");
            parametros.Append(this._paqueteEjecutar);
            parametros.Append("\"");
            //parametros.Append(" ");
            parametros.Append(" /ser ");
            //parametros.Append(" ");
            parametros.Append(this._serverPkg);
            //parametros.Append(" ");
            //añadimos las variables
            foreach (var variable in this.ValoresYVariables.Where(variable => !String.IsNullOrEmpty(variable.Value)))
            {
                parametros.Append(@" /set ");
                  parametros.Append("\"\\Package.Variables[");
                parametros.Append(variable.Key);
                parametros.Append("].Properties[Value]\";");
                parametros.Append("\"");
                parametros.Append(variable.Value);
                parametros.Append("\"");
            }
            return parametros.ToString();
        }

        /// <summary>
        /// Coloca los valores de las variables en la lista
        /// </summary>
        /// <param name="valoresVariables"></param>
        private void SetValoresVariables(Dictionary<string, string> valoresVariables)
        {
            var dict = new Dictionary<string, string >(valoresVariables);
            foreach (KeyValuePair<string, string> variable in dict)
            {
                if (this.ValoresYVariables.Keys.Contains(variable.Key))
                {
                    if (variable.Key == this.varFilePath)
                    {
                        this.ValoresYVariables[variable.Key] = GetFilePath(variable.Value);
                    }
                    else
                    {
                        this.ValoresYVariables[variable.Key] = variable.Value;
                    }
                }
                
            }           
        }

        /// <summary>
        /// el nombre de la carpeta donde se deben de encontrar los archivos los ponemos para que estén en la ruta con las diagonales
        /// invertidas por lo que para la correcta ejecución en linea de comandos la última diagonal debe de estar doble \\
        /// </summary>
        /// <param name="filepath">filepath el cual se revisará</param>
        /// <returns>string con la ruta en el formato correcto</returns>
        private string GetFilePath(string filepath)
        {
            var retorno = filepath.Replace('/','\\');
            if (retorno.EndsWith("\\\\"))
            {
                return retorno;
            }
            if (retorno.EndsWith("\\"))
            {
                return (retorno + "\\");
            }
            return (retorno + "\\\\");
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~ExecutorDtsx()
        {
            // Finalizer calls Dispose(false)
            Dispose(false);
        }
        // The bulk of the clean-up code is implemented in Dispose(bool)
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // free managed resources
                if (this._package != null)
                {
                    this._package.Dispose();
                    this._package = null;
                }
            }
        }
    }
}
